//=============================================================================
//// Shader uses position and normal lighting
//=============================================================================
#define FOGMODE_NONE    0
#define FOGMODE_LINEAR  1
#define FOGMODE_EXP     2
#define FOGMODE_EXP2    3
#define E 2.71828
SamplerState samLinear
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Clamp;
    AddressV = Clamp;
};
RasterizerState NoCull
{
	CullMode = NONE;
};

Texture2D g_TextureDiffuse;

SamplerState gTriLinearSam
{
	Filter = MIN_MAG_MIP_LINEAR;
	AddressU = Wrap;
	AddressV = Wrap;
};
BlendState alphablend
{
	BlendEnable[0] = TRUE;
	SrcBlend = SRC_ALPHA;
	DestBlend = INV_SRC_ALPHA;
	BlendOp = ADD;
	SrcBlendAlpha = ZERO;
	DestBlendAlpha = ZERO;
	BlendOpAlpha = ADD;
	RenderTargetWriteMask[0] = 0x0F;
};
cbuffer cbChangesEveryFrame
{
	//atmospheric scattering parameters
	uniform extern float3    EyePos;
	uniform extern float3    SunDir;
	uniform extern float3    BetaRPlusBetaM;
	uniform extern float3    HGg;
	uniform extern float3    BetaDashR;
	uniform extern float3    BetaDashM;
	uniform extern float3    OneOverBetaRPlusBetaM;
	uniform extern float4    Multipliers;
	uniform extern float4    SunColorAndIntensity;
	uniform extern float4x4  WorldViewProj;
	uniform extern float4x4  WorldView;
	int      g_fogMode = FOGMODE_LINEAR;
	float    g_fogStart = 50.0f;
    float    g_fogEnd = 300.0f;
    float    g_fogDensity = 0.05f;
	float    g_fogMaxHeight = 0.05f;
    float4   g_fogColor = float4(0.7f,1.0f,1.0f,1);
}

struct InputSkyVS                                                                        
{
	float3 Position : POSITION;
	float2 TexCoord : TEXCOORD0;
}; 

struct OutputSkyVS
{
	float4 Position     : POSITION;
	float2 distance		: TEXCOORD0;
	float3 Lin          : TEXCOORD1;
	float3 Fex          : TEXCOORD2;
	float3 PosW			: TEXCOORD3;
	float2 Tex			: TEXCOORD4;
	float fogFactor		: FOGDISTANCE;
};
//Fucntions
float3 water_scattering(float3 InColor, float depth, float length)
{
	float extinction = exp(-0.02f*max(depth,0));
    float alpha = (1 - extinction*exp(-max(length,0)*0.2f));
    
    return lerp(InColor, 0.7f*float3(0.157, 0.431, 0.706), alpha);   
}
float CalcFogFactor( float d )
{
    float fogCoeff = 1.0;
    
    if( FOGMODE_LINEAR == g_fogMode )
    {
        fogCoeff = (g_fogEnd - d)/(g_fogEnd - g_fogStart);
    }
    else if( FOGMODE_EXP == g_fogMode )
    {
        fogCoeff = 1.0 / pow( E, d*g_fogDensity );
    }
    else if( FOGMODE_EXP2 == g_fogMode )
    {
        fogCoeff = 1.0 / pow( E, d*d*g_fogDensity*g_fogDensity );
    }
    
    return clamp( fogCoeff, 0, 1 );
}
//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
OutputSkyVS HoffmanSkyVS ( InputSkyVS IN )
{
	//                                                                                  
	// Calculate view direction and distance                                            
	//                                                                                  
																						
	float3 vertex        = mul(WorldView, IN.Position).xyz;                                  
	float3 viewDirection = normalize( vertex );                                         
	float  distance      = length( vertex );                                       
																						
	//                                                                                  
	// Angle between sun direction and view direction                                   
	//                                                                                  
																						
	float3 sunDirection = normalize(mul(WorldView, float4(SunDir, 1.0)).xyz );              
	float  theta        = dot( sunDirection, viewDirection );                           
																						
	//                                                                                  
	// Phase1 and Phase2                                                                
	//                                                                                  
																						
	float phase1 = 1.0 + theta * theta;                                                 
	float phase2 = pow( rsqrt( HGg.y - HGg.z * theta ), 3 ) * HGg.x;                    
																						
	//                                                                                  
	// Extinction term                                                                  
	//                                                                                  
																						
	float3 extinction      = exp( -BetaRPlusBetaM * distance );                         
	float3 totalExtinction = extinction * Multipliers.yzw;                              
																						
	//                                                                                  
	// Inscattering term                                                                
	//                                                                                  
																						
	float3 betaRay = BetaDashR * phase1;                                                
	float3 betaMie = BetaDashM * phase2;                                                
																						
	float3 inscatter = (betaRay + betaMie) * OneOverBetaRPlusBetaM * (1.0 - extinction);
																						
	//                                                                                  
	// Apply inscattering contribution factors                                          
	//                                                                                  
																						
	inscatter *= Multipliers.x;                                                         
																						
	//                                                                                  
	// Scale with sun color & intensity                                                 
	//                                                                                  
																						
	inscatter       *= SunColorAndIntensity.xyz * SunColorAndIntensity.w;               
	totalExtinction *= SunColorAndIntensity.xyz * SunColorAndIntensity.w;               
																						
	//                                                                                  
	// Transform vertex and set its colors              
																						
	//                                                                                  
	// Transform vertex and set its colors                                              
	//                                                                                  
																						
	OutputSkyVS OUT;                                                                      
																						
	OUT.Position	= mul(float4(IN.Position, 1.0f), WorldViewProj);
	OUT.PosW		= mul(float4(IN.Position, 1.0f), WorldView);
	OUT.distance	= distance;
	OUT.distance.y	= EyePos.y;                                                
	OUT.Lin         = inscatter;                                                       
	OUT.Fex         = totalExtinction;                                                 
	OUT.Tex			= IN.TexCoord;		
	OUT.fogFactor	= EyePos.z;																
	return OUT;     
}
//--------------------------------------------------------------------------------------
// Pixel XMeshShader
//--------------------------------------------------------------------------------------
float4 HoffmanSkyPS( OutputSkyVS IN ) : SV_Target
{
	float3 final = IN.Lin;
	
	//hack to make the sky dome the same color as the water when the camera
	//is below the water line. if our terrain was big enough we wouldn't need to do this
	//if(EyePos.y <= 0 && IN.PosW.y <= 5.0f)
    //{
		//final = water_scattering(final.rgb, IN.distance.y, IN.distance.x);
	//}

	float heightfog = max(g_fogMaxHeight - IN.PosW.y, 0.0f) / (g_fogMaxHeight * g_fogDensity);

	float fog = CalcFogFactor(length(IN.PosW - EyePos) * heightfog);
	//fog *= g_fogDensity;

	float3 color = g_TextureDiffuse.Sample(gTriLinearSam, IN.Tex ).rgb;
	//color *= SunColorAndIntensity.w;// / 100.0f;
	// Hack Sky Night Color
	//float stars = 1.0f - (final.r + final.g + final.b) / 1.2675f;

	final.rgb += max(0,(1 - final.rgb)) * 0.5f *color;//(float3( 0.05, 0.05, 0.1 ));
	//final.rgb += color *  max(0,(1 - (IN.Fex / 100)));
	//float3 stars = lerp(color, final, color.b);
	//final += color * (1.0f - SunColorAndIntensity.w);
	//return color;
	float4 finalcolor = fog * float4(final, 1.0f) + (1.0 - fog)*g_fogColor;
	return finalcolor;
}

DepthStencilState DepthEnabling
{
    //DepthEnable = FALSE;
	DepthFunc = LESS_EQUAL;
};

technique10 Render
{
    pass P0
    {
		SetVertexShader( CompileShader( vs_4_0, HoffmanSkyVS() ) );
        SetGeometryShader( NULL );
        SetPixelShader( CompileShader( ps_4_0, HoffmanSkyPS() ) );
        SetRasterizerState(NoCull);
		//SetDepthStencilState(DepthEnabling, 0);
    }
}
